package com.liaoyifan.core.opera;

import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.liaoyifan.core.enums.CoreCodeEnum;
import com.liaoyifan.core.model.Result;
import com.liaoyifan.core.util.Json;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

@SuppressWarnings("unused")
@Log4j2
public class SentinelExceptionHandler implements BlockExceptionHandler {

    @Override
    public void handle(
            HttpServletRequest request,
            HttpServletResponse response,
            String resource,
            BlockException e)
            throws Exception {
        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        try (PrintWriter writer = response.getWriter()) {
            writer.write(Json.toString(result(request, resource, e)));
        }
    }

    public static Result<Map<String, String>> result(
            HttpServletRequest request, String resource, BlockException e) {
        Map<String, String> data = new HashMap<>(4);
        AbstractRule rule = e.getRule();
        data.put("resource", resource != null ? resource : rule != null ? rule.getResource() : "");
        data.put("path", request.getRequestURI());
        data.put("type", e.getClass().getSimpleName());
        data.put("rule", rule != null ? rule.toString() : "");
        log.warn(
                "[Sentinel Block] Resource: {} | Path: {} | Type: {} | Rule: {}",
                data.get("resource"),
                data.get("path"),
                data.get("type"),
                data.get("rule"));
        return Result.error(
                CoreCodeEnum.BLOCK_EXCEPTION.getCode(),
                HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase(),
                data);
    }
}
